/*
 * Copyright (C) 2006-2012 TongYan Corporation
 * All rights reserved.
 *
 * @brief info:
 *
 * @author: 王哲成 - wangzhecheng@yeah.net
 * @date: 2021.05.25
 * @last modified: 2021-05-25 10:38
 *
 */

#include "../include/LocalSearchMethod.hpp"

Candidate LocalSearchMethod::getOptimalSolution(const ParamSet &param_set) {
  assert(m_nSeedNum > 0);
  assert(m_dEpsilon > 0);

  // 1. 布随机点
  std::vector<Candidate> seeds;
  srand((int)time(0));                 // 产生随机种子
  size_t nParamNum = param_set.size(); // 参数个数
  for (size_t i = 0; i != m_nSeedNum; i++) {
    Vector param_value = Vector::Zero(nParamNum);
    for (size_t idx = 0; idx != nParamNum; idx++)
      param_value[idx] =
          random_between(param_set.lBound(idx), param_set.uBound(idx));

    double fx = m_ptrTarFunc->functionValue(param_value);
    seeds.push_back(std::make_pair(param_value, fx));
  }

  // 2. 每点进入步进阶段，找到极小值
  // TODO: 加入并行
  for (auto seed : seeds) {
    bool convergenced = false;
    while (convergenced) {
      convergenced = updateSearchPoint(param_set, seed);
    }
  }

  // 3. 比较各点找到的极小值，以找到最小值
  auto min_position = std::min_element(
      seeds.begin(), seeds.end(), [](const Candidate &p1, const Candidate &p2) {
        return p1.second > p2.second;
      });
  // 4.
  return *min_position;
}
double LocalSearchMethod::Armijo(
    const Vector &x,  // x的值
    const Vector &dx, // x偏移量（求差分用）
    const Vector &dk, // f(x)下降方向
    const double &gamma, // 参数gamma,斜率折减系数，取值(0,0.5)越大越快
    const double &sigma, // 参数sigma,步长缩减比例，取值(0,1),越大越慢
    const size_t &iterMax) const //最大迭代次数
{
  double lambda = 1;

  for (size_t iter = 0; iter != iterMax; iter++) {
    Vector x_new = x + lambda * dk;
    if (m_ptrTarFunc->functionValue(x_new) <=
        m_ptrTarFunc->functionValue(x) +
            gamma * lambda *
                m_ptrTarFunc->gradientVector(x, dx).dot(dk)) // Armijo准则
      return lambda;
    else
      lambda *= sigma;
  }

  return lambda;
}
